# -*- coding: utf-8 -*-
"""
Created on Mon Oct 14 16:51:55 2019

@author: ASUS
"""
import random
import csv#csv包可以读写csv文件
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from IPython.display import display

#读取数据
def read_datasets(path):
    with open(path,'r') as file:
        reader = csv.DictReader(file)
        datas = [row for row in reader]
        return datas
       
#分组
def train_test_split(datas,m):#假设数据集总量为M,则测试集为M/m个，训练集为M/(M-m)个
    random.shuffle(datas)#将数据集打乱顺序
    n = len(datas) // m #整除，避免出现小数
    test_set = datas[0:n]#测试集  第0个到第n个不包含第n个
    train_set = datas[n:]#训练集 从n开始到最后 
    return test_set,train_set
    
#算距离(欧氏距离)
def eculid_distance(di,d):
    res = 0#用于求和
    for key in('sepal_length','sepal_width','petal_length','petal_width'):
        res += (float(di[key]) - float(d[key])) ** 2
    return res ** 0.5
 
#Knn分类算法
def knn(data,K,train_set):
   
#        KNN算法过程
#        1.求距离
#        2.排序——升序
#        3.取前K个
#        4.加权平均
   
   #1.求距离
    res = [
       {"result":train['species'],"distance":eculid_distance(data,train)}
       for train in train_set
    ]
    #排序-升序
    res = sorted(res,key = lambda item:item['distance'])
    #取前K个
    resK = res[0:K]
#   print(resK)
    #4.加权平均(离的近的权重高，离得远的权重低)
    result = {'setosa':0,'versicolor':0,'virginica':0}
    #算前K个的总距离
    sum_distance = 0
    for r in resK:
      sum_distance += r['distance']
    for r in resK:
       result[r['result']] += 1 - r['distance']/sum_distance#计算权重
#    print(result)
#    print(data['species'])
    return(sorted(result,key = lambda x:result[x])[-1])#返回字典中最大value对应的key


if __name__ == '__main__':
#    n是取临近的几个邻居
    K = 5
    datas = read_datasets('iris.csv')
    test_set,train_set = train_test_split(datas,3)
#    result = knn(test_set[0],K,train_set)#用第0个测试项做测试
    #预估结果
    correct = 0
    for test in test_set:
        result = test['species']#result是测试集的真实结果
        result_predict = knn(test,K,train_set)#result_predict是预估的结果    
        if result == result_predict:
            correct += 1
    score =  100*correct/len(test_set)       
    print("test accuracy:{:.2f}".format(score/100))
    
    
    